#!/usr/bin/env python

#################################################################################
#
# Copyright (c) 2006 Michigan State University
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#################################################################################

#################################################################################
#
#	Author:
#		Nathan Collins <npcollins@gmail.com>
#
#################################################################################

"""
When all else fails, do it yourself.

The OAI xml parsing classes/functions.
"""

import xml.sax
from types import *
import urllib
import httpget
from time import sleep
from oailog import *
from utility import *
from preprocess import preprocess

class xmlObj:
	def __init__(self):
		# name of the element
		self.name = ''
		# attribute dictionary
		self.attr = {}
		# child elements
		self.child = []
		# contents
		self.content = ''
	
	def setName(self,name):
		self.name = name

	def getName(self):
		return self.name

	def setAttr(self,attr):
		self.attr = attr

	def addAttr(self,name,value):
		self.attr[name] = value

	def getAttr(self):
		return self.attr

	def addChild(self,child):
		self.child.append(child)

	def getChild(self):
		return self.child

	def setContent(self,content):
		self.content += content

	def getContent(self):
		return self.content


class OAISaxHandler(xml.sax.handler.ContentHandler):
	def __init__(self):
		# root object (empty)
		self.root = xmlObj()
		# parent of current object
		self.par = None
		# parent list
		self.kin = []
		# current object
		self.cur = self.root

	def getRoot(self):
		return self.root
	
	def startDocument(self):
		pass

	def endDocument(self):
		pass

	def startElement(self, name, attr):
		self.kin.append(self.par)
		self.par = self.cur
		self.cur = xmlObj()
		self.par.addChild(self.cur)
		self.cur.setName(name)
		if attr.getLength() > 0:
			attrs = dict([(n, attr.getValue(n)) for n in attr.getNames()])
			self.cur.setAttr(attrs)

	def endElement(self, name):
		self.cur = self.par
		self.par = self.kin.pop()

	def characters(self, chars):
		if len(chars.strip()) > 0:
			self.cur.setContent(chars)

def getXML(url, secondtry = 0):
	file = httpget.getURL(url)
	# preprocess the data
	file = preprocess(file)
	
	handler = OAISaxHandler()
	try:
		xml.sax.parseString(file,handler)
	except:
		if secondtry:
			# Server did not return XML
			swrite('M')
			hErr('Server failed to provide XML: %s' % url)
			return None
		else:
			# server did not respond with xml, hold and try again
			# print '[Retrying]'
			sleep(5)
			return getXML(url, 1)
			
	return handler.getRoot()

def xmlToDict(xmlRoot):
	d = {}
	return processChild( d, xmlRoot.getChild() )

def processChild(parent,childList):
	for c in childList:
		# if it's a duplicate tag, append
		if c.getName() in parent:
			parent[c.getName()]['value'] += '\n' + c.getContent()
			# attributes shouldn't be on duplicate tags
		# create new tag
		else:
			parent[c.getName()] = { 'value':c.getContent(), 'attr':c.getAttr() }
		parent[c.getName()] = processChild( parent[c.getName()], c.getChild() )
	return parent

def processList(xmlRoot):
	list = getChildList([xmlRoot],'ListRecords')

def getChildList(xmlList, stopTag):
	# iterate down in tree until the stoptag is found, return that level
	for c in xmlList:
		if c.getName() == stopTag:
			# found it
			list = []
			for t in c.getChild():
				rec = xmlToDict(t)
				if len(rec) > 0: list.append(rec)
			return list
		else:
			if len(c.getChild()) > 0:
				sub = getChildList(c.getChild(),stopTag)
				if len(sub) > 0: return sub
	return []

# eof

